home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks ’90 / ShrinkToFit ƒ / stfinit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-15  |  5.8 KB  |  223 lines  |  [TEXT/KAHL]

  1. /* This is the source to ShrinkToFit, an init that shrinks Think C windows to fit around the
  2.  * current selection.  As it exists, it only works for Think C, but it could probably be adapted
  3.  * to your favorite text editor.
  4.  * 
  5.  * The way it works:
  6.  *        It inserts an JGNEFilter proc.  This looks for control-clicks in the zoom box.  It
  7.  *        diddles the zoom rects to get THC to resize the window appropriately.  It also
  8.  *        posts an "enter" key to get THC to center the current selection in the window.
  9.  *        When the filterproc gets the key event, it restores the zoom rects so that you
  10.  *        can zoom normally.
  11.  *
  12.  * Copyright © 1990 Meredith Lesly.  All rights reserved
  13.  */
  14.  
  15. #ifndef _MacTypes_
  16. #include <MacHeaders>
  17. #endif
  18. #include <PE.h>
  19.  
  20. static Boolean    nextEnter;        /* Flag to indicate whether to restore the old zoom box */
  21. static ProcPtr    oldProc;
  22.  
  23. #define MINLINES        7
  24. #define VMARGIN            24
  25.  
  26. typedef struct {
  27.     WStateData            theUsual;
  28.     Rect                oldStdState;
  29. } ExtWStateData;
  30.  
  31. void jgneHook();
  32.  
  33. main()
  34. {
  35.     long saveA4;
  36.     
  37.     asm {
  38.     
  39.     /* Make globals addressable */
  40.         move.l    a4,saveA4
  41.     
  42.     /* Recover and detach myself.  I'm already locked. */
  43.         lea        main,a0
  44.         move.l    a0,a4
  45.         _RecoverHandle
  46.         move.l    a0,-(sp)
  47.         _DetachResource
  48.     }
  49.     
  50.     /* Clear a flag */
  51.     nextEnter = FALSE;
  52.     
  53.     /* Stash teh old filter */
  54.     oldProc = JGNEFilter;    
  55.     JGNEFilter = (void *)jgneHook;
  56.  
  57.     /* restore a4 */
  58.     asm {
  59.         move.l    saveA4,a4
  60.     }
  61. }
  62.  
  63. void jgneHook()
  64. {
  65.     long    saveA4;
  66.  
  67.     asm {
  68.         move.l    a4,saveA4            ; save a4
  69.         lea        main,a4                ; set up for globals
  70.     }
  71.     doIt();
  72.     asm {
  73.         move.l    oldProc,a0
  74.         move.l    saveA4,a4
  75.         unlk    a6
  76.         move.b    4(sp),d0
  77.         jmp        (a0)
  78.     }
  79. }
  80.         
  81. doIt()
  82. {
  83.     register EventRecord    *ep;
  84.     WindowPtr                wPtr;
  85.     short                    part;
  86.     EvQElPtr                q;
  87.  
  88.     asm {
  89.         move.l    a1,ep                ; rescue eventrecord ptr
  90.     }
  91.     if (nextEnter == TRUE) {        /* do we want to fix zoom rects now? */
  92.         ExtWStateData *stateData;
  93.  
  94.         if (ep->what != keyDown)
  95.             goto exit;
  96.         nextEnter = FALSE;
  97.         wPtr = FrontWindow();
  98.         stateData = *(ExtWStateData **)((WindowPeek)FrontWindow())->dataHandle;
  99.         stateData->theUsual.stdState = stateData->oldStdState;
  100.         goto exit;
  101.     }
  102.     else if ((ep->what != mouseDown) || ((ep->modifiers & controlKey) == 0))
  103.         goto exit;
  104.  
  105.     part = FindWindow(ep->where, &wPtr);
  106.     if (part != inZoomIn && part != inZoomOut)
  107.         goto exit;
  108.     
  109.     diddleZoom(wPtr);
  110.     nextEnter = TRUE;
  111.  
  112.     PPostEvent(keyDown, 0x4c03, &q);        /* Post the enter key */
  113.     q->evtQModifiers = 0;        /* Make sure the modifiers keys are clear! */
  114.     
  115. exit:
  116.     asm {
  117.         move.l    ep,a1
  118.         clr.l    d0
  119.     }
  120. }
  121.  
  122. diddleZoom(WindowPeek wPtr)
  123. {
  124.     register short        nLines, v, h;
  125.     PEHandle            hPE;
  126.     long                selStart, selEnd;
  127.     short                startLine, endLine;
  128.     short                i;
  129.     register ExtWStateData *p;
  130.     EventRecord            e;
  131.     EvQElPtr            q;
  132.     Rect                curBounds;
  133.     short                newTop;
  134.  
  135.     if (!EqualString(CurApName, "\pTHINK C", FALSE, FALSE)) {
  136.         SysBeep(1);
  137.         return;
  138.     }
  139.  
  140.     if (wPtr->dataHandle == 0 || (wPtr->windowKind != 0x0B && wPtr->windowKind != 0x0C))
  141.         return;
  142.         
  143.     SetPort(wPtr);
  144.     /* Rescue the PEHandle.  This is slightly proprietary, but others have figured it
  145.      * out, so what's the big deal?
  146.      */
  147.     hPE = *(PEHandle *)(4 + *(Handle)wPtr->refCon);
  148.     
  149.     /* This is all PE stuff, of course, similar to TE.  I wish I could put in some 
  150.      * propaganda about buying Capps`, since I worked on the package, but since it's
  151.      * not on the market anymore <<sigh>> it'll just frustrate you.  I'll explain the
  152.      * logic, since this FKEY is fairly adaptable to TE-based editors
  153.      */
  154.      
  155.     /* Get the start line and end line of the selection.  The minimum size of
  156.      * a THINK C window is seven lines, so we adjust the startLine and number of
  157.      * lines
  158.      */
  159.     
  160.     /* PELineNum returns the line number of a character */
  161.     startLine = PELineNum((**hPE).selStart, hPE);
  162.     if (startLine > (**hPE).nLines - MINLINES)
  163.         startLine = (**hPE).nLines - MINLINES;
  164.     endLine = PELineNum((**hPE).selEnd, hPE);
  165.     nLines = 2 + endLine - startLine;
  166.     if (nLines < MINLINES)
  167.         nLines = MINLINES;
  168.     
  169.     /* Figure out the new upper left corner of the window */
  170.     
  171.     newTop = 23 + (**hPE).lineHeight * (startLine - (**hPE).viewOrgV);
  172.     
  173.     /* I just figured out VMARGIN by varying it.  It seem to be about right */
  174.     v = nLines * (**hPE).lineHeight + VMARGIN;
  175.     
  176.     /* The fun part -- figuring out the longest selected line.  This is really the
  177.      * reason we need PE–specific stuff, since the selected lines might be possible
  178.      * to figure out heuristically.
  179.      */
  180.     for (i = startLine; i <= endLine; i++) {
  181.         long charno, eol;
  182.         short len;
  183.  
  184.         /* PECharPos returns the first character on a line (i, in this case) */
  185.         charno = PECharPos(i, hPE);
  186.         /* PEEol returns the last character on the line that character charno is on */
  187.         eol = PEEol(charno, hPE);
  188.         /* PEOffsetH returns the pixel offset to a character */
  189.         len = PEOffsetH(eol, hPE);
  190.         if (h < len)
  191.             h = len;
  192.     }
  193.     h += 20;
  194.     
  195.     /* Since we're called "ShrinkToFit", we don't really want to *grow* the window,
  196.      * so limit the size to the current one
  197.      */
  198.     curBounds = ((WindowPtr)wPtr)->portRect;
  199.     if (h > curBounds.right - curBounds.left)
  200.         h = curBounds.right - curBounds.left;
  201.     if (v > curBounds.bottom - curBounds.top)
  202.         v = curBounds.bottom - curBounds.top;
  203.     
  204.     /* We're going to extend the dataHandle to include the old stdState (fully-zoomed
  205.      * size), so that we can set it back after the window is resized
  206.      */
  207.     SetHandleSize(wPtr->dataHandle, sizeof(ExtWStateData));
  208.     p = *(ExtWStateData **) wPtr->dataHandle;
  209.     
  210.     /* Shrink it using the old upper-left hand corner.  It would probably be more
  211.      * elegant to tile the suckers, but I don't feel like doing it right now
  212.      */
  213.     p->theUsual.userState.right = p->theUsual.userState.left + h;
  214.     p->theUsual.userState.bottom = p->theUsual.userState.top + v;
  215. #if 0
  216.     OffsetRect(&p->theUsual.userState, 0, newTop);
  217. #endif
  218.     
  219.     p->oldStdState = p->theUsual.stdState;
  220.     p->theUsual.stdState = curBounds;
  221.     LocalToGlobal(&topLeft(p->theUsual.stdState));
  222.     LocalToGlobal(&botRight(p->theUsual.stdState));
  223. }